/* ** HDL4SE: 软件Verilog综合仿真平台 ** Copyright (C) 2021-2021, raoxianhong ** LCOM: 轻量级组件对象模型 ** Copyright (C) 2021-2021, raoxianhong ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are met: ** ** * Redistributions of source code must retain the above copyright notice, ** this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright notice, ** this list of conditions and the following disclaimer in the documentation ** and/or other materials provided with the distribution. ** * The name of the author may be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ** THE POSSIBILITY OF SUCH DAMAGE. */ /* * terisctrl_1.c 修改记录: 202106201016: rxh, initial version */ #include "stdlib.h" #include "stdio.h" #include "string.h" #include "object.h" #include "dlist.h" #include "bignumber.h" #include "hdl4secell.h" #include "terris.h" #include "terrisengine1.h" /* 0: input wClk, 1: input nwReset, 2: output wWrite, 3: output[5:0] bWriteAddr, 4: output[63:0] bWriteData, 5: output[5:0] bReadAddr, 6: input[63:0] bReadData, 7: input[31:0] bKeyData, 8: input wStateComplete, 9: output wStateChange, 10: output[3:0] bState, 11: output[31:0] bScore, 12: output[31:0] bSpeed, 13: output[31:0] bLevel, 14: output [63:0] bNextBlock, 15: output [63:0] bCurBlock; 16: output [15:0] bCurBlockPos; */ struct _sTerrisCtrl1; typedef struct _sTerrisCtrl1 sTerrisCtrl1; struct _sTerrisCtrl1 { OBJECT_HEADER INTERFACE_DECLARE(IHDL4SEUnit) HDL4SEUNIT_VARDECLARE DLIST_VARDECLARE IHDL4SEModule** parent; char* name; IHDL4SEUnit** readdata_unit; int readdata_index; IBigNumber** readdata; IHDL4SEUnit** keydata_unit; IBigNumber** keydata; IBigNumber** lastkeydata; int keydata_index; IHDL4SEUnit** statecomplete_unit; int statecomplete_index; IBigNumber** statecompletedata; unsigned int write; unsigned int writeaddr; unsigned long long writedata; unsigned int readaddr; unsigned int write_reg; unsigned int writeaddr_reg; unsigned long long writedata_reg; unsigned int readaddr_reg; struct tagGenContext { int index; int complete; int count; int startindex; }genContext; struct tagBlockCanSetToContext { int nextstate; int param; int result; int index; int x; int y; int complete; void (*BlockCanSetToPro)(sTerrisCtrl1 * pobj); }blockCanSetToContext; int state; int laststate; }; OBJECT_FUNCDECLARE(terrisctrl1, CLSID_TERRISCTRL1); HDL4SEUNIT_FUNCDECLARE(terrisctrl1, CLSID_TERRISCTRL1, sTerrisCtrl1); DLIST_FUNCIMPL(terrisctrl1, CLSID_TERRISCTRL1, sTerrisCtrl1); OBJECT_FUNCIMPL(terrisctrl1, sTerrisCtrl1, CLSID_TERRISCTRL1); QUERYINTERFACE_BEGIN(terrisctrl1, CLSID_TERRISCTRL1) QUERYINTERFACE_ITEM(IID_HDL4SEUNIT, IHDL4SEUnit, sTerrisCtrl1) QUERYINTERFACE_ITEM(IID_DLIST, IDList, sTerrisCtrl1) QUERYINTERFACE_END static const char* terrisctrl1ModuleInfo() { return "1.0.0-20210620.1016 Terris Controller V1"; } static int terrisctrl1Create(const PARAMITEM* pParams, int paramcount, HOBJECT* pObject) { sTerrisCtrl1* pobj; int i; pobj = (sTerrisCtrl1*)malloc(sizeof(sTerrisCtrl1)); if (pobj == NULL) return -1; *pObject = 0; HDL4SEUNIT_VARINIT(pobj, CLSID_TERRISCTRL1); INTERFACE_INIT(IHDL4SEUnit, pobj, terrisctrl1, hdl4se_unit); DLIST_VARINIT(pobj, terrisctrl1); pobj->name = NULL; pobj->parent = NULL; pobj->keydata_unit = NULL; pobj->keydata = bigintegerCreate(32); pobj->lastkeydata = bigintegerCreate(32); pobj->statecomplete_unit = NULL; pobj->statecompletedata = bigintegerCreate(1); pobj->readdata_unit = NULL; pobj->readdata = bigintegerCreate(64); for (i = 0; i < paramcount; i++) { if (pParams[i].name == PARAMID_HDL4SE_UNIT_NAME) { if (pobj->name != NULL) free(pobj->name); pobj->name = strdup(pParams[i].pvalue); } else if (pParams[i].name == PARAMID_HDL4SE_UNIT_PARENT) { pobj->parent = (IHDL4SEModule **)pParams[i].pvalue; } } pobj->genContext.index = 0; pobj->write = 0; pobj->state = ST_INIT; pobj->laststate = ST_INIT; terrisInit(); /* 返回生成的对象 */ OBJECT_RETURN_GEN(terrisctrl1, pobj, pObject, CLSID_TERRISCTRL1); return EIID_OK; } static void terrisctrl1Destroy(HOBJECT object) { sTerrisCtrl1* pobj; int i; pobj = (sTerrisCtrl1*)objectThis(object); if (pobj->name != NULL) free(pobj->name); memset(pobj, 0, sizeof(sTerrisCtrl1)); free(pobj); } static int terrisctrl1Valid(HOBJECT object) { sTerrisCtrl1* pobj; pobj = (sTerrisCtrl1*)objectThis(object); return 1; } static int terrisctrl1_hdl4se_unit_GetName(HOBJECT object, const char** pname) { sTerrisCtrl1* pobj; pobj = (sTerrisCtrl1*)objectThis(object); *pname = pobj->name; return 0; } static int terrisctrl1_hdl4se_unit_Connect(HOBJECT object, int index, HOBJECT from, int fromindex) { sTerrisCtrl1* pobj; IHDL4SEUnit** unit = NULL; pobj = (sTerrisCtrl1*)objectThis(object); if (index == 6) { if (0 == objectQueryInterface(from, IID_HDL4SEUNIT, (void**)&unit)) { objectRelease(pobj->readdata_unit); pobj->readdata_unit = unit; pobj->readdata_index = fromindex; } } else if (index == 7) { if (0 == objectQueryInterface(from, IID_HDL4SEUNIT, (void**)&unit)) { objectRelease(pobj->keydata_unit); pobj->keydata_unit = unit; pobj->keydata_index = fromindex; } } else if (index == 8) { if (0 == objectQueryInterface(from, IID_HDL4SEUNIT, (void**)&unit)) { objectRelease(pobj->statecomplete_unit); pobj->statecomplete_unit = unit; pobj->statecomplete_index = fromindex; } } return 0; } static int terrisctrl1_hdl4se_unit_ConnectPart(HOBJECT object, int index, int start, int width, HOBJECT from, int fromindex) { sTerrisCtrl1* pobj; IHDL4SEUnit** unit = NULL; pobj = (sTerrisCtrl1*)objectThis(object); return 0; } static int terrisctrl1_hdl4se_unit_GetValue(HOBJECT object, int index, int width, IBigNumber ** value) { int i; sTerrisCtrl1* pobj; pobj = (sTerrisCtrl1*)objectThis(object); if (index == 2) { objectCall1(value, AssignUint32, pobj->write_reg); } else if (index == 3) { objectCall1(value, AssignUint32, pobj->writeaddr_reg); } else if (index == 4) { objectCall1(value, AssignUint64, pobj->writedata_reg); } else if (index == 5) { objectCall1(value, AssignUint32, pobj->readaddr_reg); } else if (index == 9) { objectCall1(value, AssignUint32, pobj->state != pobj->laststate); } else if (index == 10) { objectCall1(value, AssignUint32, pobj->state); } else if (index == 11) { objectCall1(value, AssignUint32, gameScore); } else if (index == 12) { objectCall1(value, AssignUint32, MAXSPPED - currentspeed); } else if (index == 13) { objectCall1(value, AssignUint32, gameLevel); } else if (index == 14) { unsigned long long data; int i, j; data = 0; for (i = 0; i < BLOCKSIZE; i++) { for (j = 0; j < BLOCKSIZE; j++) { data <<= 4; data |= nextblock.subblock[BLOCKSIZE - 1 - i][BLOCKSIZE-1-j] & 0xf; } } objectCall1(value, AssignUint64, data); } else if (index == 15) { unsigned long long data; int i, j; data = 0; for (i = 0; i < BLOCKSIZE; i++) { for (j = 0; j < BLOCKSIZE; j++) { data <<= 4; data |= currentblock.subblock[BLOCKSIZE - 1 - i][BLOCKSIZE - 1 - j] & 0xf; } } objectCall1(value, AssignUint64, data); } else if (index == 16) { objectCall1(value, AssignUint32, ((currentblock.posx + 1) & 0xff) | ( ((YCOUNT-1-currentblock.posy) & 0xff) << 8)); } return 0; } static void terrisctrl1_hdl4se_unit_PressKeyPro(sTerrisCtrl1* pobj) { switch (pobj->blockCanSetToContext.param) { case TK_LEFT:/*left*/ if (pobj->blockCanSetToContext.result) currentblock.posx--; break; case TK_DOWN:/*down*/ break; case TK_RIGHT:/*right*/ if (pobj->blockCanSetToContext.result) currentblock.posx++; break; case TK_TURNLEFT:/*逆时针1*/ if (pobj->blockCanSetToContext.result == 0) terrisBlockRotate(¤tblock, 0); break; case TK_TURNRIGHT:/*顺时针0*/ if (pobj->blockCanSetToContext.result == 0) terrisBlockRotate(¤tblock, 1); break; } } static void terrisctrl1_hdl4se_unit_AfterCheckLine(sTerrisCtrl1* pobj) { if (pobj->blockCanSetToContext.result == 0) { terrisInit(); pobj->genContext.index = 0; pobj->state = ST_INIT; } else { terrisGenNewBlock(&nextblock); pobj->state = ST_FLUSHTODISP; } } static void terrisctrl1_hdl4se_unit_MoveDownPro(sTerrisCtrl1* pobj) { if (pobj->blockCanSetToContext.result) { currentblock.posy++; } else { pobj->genContext.index = 0; pobj->state = ST_BLOCKWRITE; } return; } static void terrisctrl1_hdl4se_unit_BlockWrite(sTerrisCtrl1* pobj) { /*先读后写*/ int i, x, y; i = pobj->genContext.index; y = currentblock.posy - BLOCKSIZE / 2 + i+1; pobj->readaddr = YCOUNT-1-y; pobj->write = 0; pobj->genContext.complete = 0; if (pobj->genContext.index > 1) { unsigned long long line; unsigned long long blockline; i = pobj->genContext.index - 2; /*数据比索引晚两拍*/ y = currentblock.posy - BLOCKSIZE / 2 + i+1; x = currentblock.posx - BLOCKSIZE / 2; if (y < YCOUNT && y>=0) { blockline = currentblock.subblock[i][3] & 0xF; blockline <<= 4; blockline |= currentblock.subblock[i][2] & 0xF; blockline <<= 4; blockline |= currentblock.subblock[i][1] & 0xF; blockline <<= 4; blockline |= currentblock.subblock[i][0] & 0xF; pobj->writeaddr = YCOUNT - 1 - y; pobj->write = 1; objectCall3(pobj->readdata_unit, GetValue, pobj->readdata_index, 64, pobj->readdata); objectCall1(pobj->readdata, GetUint64, &line); if (x < 0) pobj->writedata = line | (blockline >> (-x * 4)); else pobj->writedata = line | (blockline << (x * 4)); } } pobj->genContext.index++; if (pobj->genContext.index > BLOCKSIZE + 1) { pobj->genContext.complete = 1; } } static void terrisctrl1_hdl4se_unit_CopyLines(sTerrisCtrl1* pobj) { pobj->readaddr = pobj->genContext.index + 1; pobj->write = 0; if (pobj->genContext.index - pobj->genContext.startindex > 1) { int index = pobj->genContext.index - 1; unsigned long long line; if (index == YCOUNT-1) { line = 0; } else { objectCall3(pobj->readdata_unit, GetValue, pobj->readdata_index, 64, pobj->readdata); objectCall1(pobj->readdata, GetUint64, &line); } if (index < YCOUNT) { pobj->write = 1; pobj->writeaddr = index; pobj->writedata = line; } if (index >= YCOUNT || line == 0) { pobj->genContext.index = 0; pobj->state = ST_CHECKLINE; return; } } pobj->genContext.index++; } static void terrisctrl1_hdl4se_unit_CheckLine(sTerrisCtrl1* pobj) { pobj->readaddr = pobj->genContext.index; pobj->genContext.complete = 0; if (pobj->genContext.index > 1) { unsigned long long line = 0; int i; objectCall3(pobj->readdata_unit, GetValue, pobj->readdata_index, 64, pobj->readdata); objectCall1(pobj->readdata, GetUint64, &line); for (i = 0; i < XCOUNT; i++) { if ((line & 0xf) == 0) break; line >>= 4; } if (i == XCOUNT) { pobj->genContext.index -= 2; pobj->genContext.startindex = pobj->genContext.index; pobj->readaddr = pobj->genContext.index + 1; pobj->state = ST_COPYLINES; pobj->genContext.count++; return; } } if (pobj->genContext.index >= YCOUNT + 1) { pobj->genContext.complete = 1; } pobj->genContext.index++; if (pobj->genContext.complete) { memcpy(¤tblock, &nextblock, sizeof(currentblock)); pobj->blockCanSetToContext.nextstate = ST_FLUSHTODISP; pobj->blockCanSetToContext.param = 0; pobj->blockCanSetToContext.result = 0; pobj->blockCanSetToContext.complete = 0; pobj->blockCanSetToContext.index = 0; pobj->blockCanSetToContext.BlockCanSetToPro = terrisctrl1_hdl4se_unit_AfterCheckLine; pobj->blockCanSetToContext.x = currentblock.posx; pobj->blockCanSetToContext.y = currentblock.posy; pobj->state = ST_CHECKBLOCKCANSETTO; } } static int terrisctrl1_hdl4se_unit_MoveDown(sTerrisCtrl1* pobj) { pobj->blockCanSetToContext.nextstate = ST_FLUSHTODISP; pobj->blockCanSetToContext.param = 0; pobj->blockCanSetToContext.result = 0; pobj->blockCanSetToContext.complete = 0; pobj->blockCanSetToContext.index = 0; pobj->blockCanSetToContext.BlockCanSetToPro = terrisctrl1_hdl4se_unit_MoveDownPro; pobj->blockCanSetToContext.x = currentblock.posx; pobj->blockCanSetToContext.y = currentblock.posy + 1; pobj->state = ST_CHECKBLOCKCANSETTO; return 0; } static int terrisctrl1_hdl4se_unit_Tick(sTerrisCtrl1* pobj) { currenttick++; if ((currenttick % currentspeed) == 0) { terrisctrl1_hdl4se_unit_MoveDown(pobj); return 1; } return 0; } static void terrisctrl1_hdl4se_unit_PressKeyStart(sTerrisCtrl1* pobj, int key) { pobj->blockCanSetToContext.nextstate = ST_FLUSHTODISP; pobj->blockCanSetToContext.param = key; pobj->blockCanSetToContext.result = 0; pobj->blockCanSetToContext.complete = 0; pobj->blockCanSetToContext.index = 0; pobj->blockCanSetToContext.BlockCanSetToPro = terrisctrl1_hdl4se_unit_PressKeyPro; pobj->state = ST_CHECKBLOCKCANSETTO; switch (key) { case TK_LEFT:/*left*/ gameScore--; pobj->blockCanSetToContext.x = currentblock.posx - 1; pobj->blockCanSetToContext.y = currentblock.posy; break; case TK_DOWN:/*down*/ gameScore += 2; terrisctrl1_hdl4se_unit_MoveDown(pobj); break; case TK_RIGHT:/*right*/ gameScore--; pobj->blockCanSetToContext.x = currentblock.posx + 1; pobj->blockCanSetToContext.y = currentblock.posy; break; case TK_TURNLEFT:/*逆时针1*/ gameScore--; terrisBlockRotate(¤tblock, 1); pobj->blockCanSetToContext.x = currentblock.posx; pobj->blockCanSetToContext.y = currentblock.posy; break; case TK_TURNRIGHT:/*顺时针0*/ gameScore--; terrisBlockRotate(¤tblock, 0); pobj->blockCanSetToContext.x = currentblock.posx; pobj->blockCanSetToContext.y = currentblock.posy; break; } currenttick = 0; if (gameScore < 0) { terrisInit(); pobj->genContext.index = 0; pobj->state = ST_INIT; } } static void terrisctrl1_hdl4se_unit_BlockCanSetTo(sTerrisCtrl1* pobj, TerrisBlock* pBlock, int x, int y) { #define RETURNRESULT(res) \ do { \ pobj->blockCanSetToContext.result = res; \ pobj->blockCanSetToContext.complete = 1; \ goto BlockCanSetTo_return; \ } while (0) int i; int j; int yy; i = pobj->blockCanSetToContext.index / BLOCKSIZE; yy = y - BLOCKSIZE / 2 + i + 1; pobj->readaddr = YCOUNT - 1 - yy; pobj->write = 0; pobj->blockCanSetToContext.complete = 0; if (pobj->blockCanSetToContext.index > 1) { /*从进入这个状态的第二个周期开始进行判断,此时数据已经读入到端口上*/ i = (pobj->blockCanSetToContext.index-2) / BLOCKSIZE; j = (pobj->blockCanSetToContext.index-2) % BLOCKSIZE; if (pBlock->subblock[i][j] != 0) { int xx, yy; unsigned long long line; xx = x - BLOCKSIZE / 2 + j; yy = y - BLOCKSIZE / 2 + i; if (yy < 0) goto BlockCanSetTo_return; if (yy >= PANELHEIGHT-1) RETURNRESULT(0); if (xx < 0) RETURNRESULT(0); if (xx >= PANELWIDTH) RETURNRESULT(0); objectCall3(pobj->readdata_unit, GetValue, pobj->readdata_index, 64, pobj->readdata); objectCall1(pobj->readdata, GetUint64, &line); line >>= xx * 4; line &= 0xF; if (line != 0) RETURNRESULT(0); } } if (pobj->blockCanSetToContext.index > BLOCKSIZE * BLOCKSIZE) { pobj->blockCanSetToContext.complete = 1; pobj->blockCanSetToContext.result = 1; } BlockCanSetTo_return : pobj->blockCanSetToContext.index++; return; } static void terrisctrl1_hdl4se_unit_Init(sTerrisCtrl1* pobj) { if (pobj->genContext.index < YCOUNT) { int i; unsigned long long data = 0; for (i = 0; i < 16; i++) { int c; c = ((pobj->genContext.index * (pobj->genContext.index + 2 + i)) % 14) + 2; data <<= 4; data |= c; } pobj->write = 1; pobj->writeaddr = pobj->genContext.index; pobj->writedata = 0; pobj->genContext.index++; pobj->genContext.complete = 0; } else { pobj->genContext.complete = 1; } } static int terrisctrl1_hdl4se_unit_ClkTick(HOBJECT object) { sTerrisCtrl1* pobj; unsigned int key; unsigned int statecomplete; pobj = (sTerrisCtrl1*)objectThis(object); pobj->write = 0; if (pobj->state == ST_INIT) { terrisctrl1_hdl4se_unit_Init(pobj); if (pobj->genContext.complete) { pobj->state = ST_FLUSHTODISP; } } else if (pobj->state == ST_FLUSHTODISP) { objectCall3(pobj->statecomplete_unit, GetValue, pobj->statecomplete_index, 32, pobj->statecompletedata); objectCall1(pobj->statecompletedata, GetUint32, &statecomplete); if (statecomplete != 0) pobj->state = ST_CHECKKEY; } else if (pobj->state == ST_CHECKKEY) { objectCall3(pobj->keydata_unit, GetValue, pobj->keydata_index, 32, pobj->keydata); if (!objectCall1(pobj->keydata, IsEQ, pobj->lastkeydata)) { objectCall1(pobj->keydata, GetUint32, &key); objectCall1(pobj->lastkeydata, Assign, pobj->keydata); if (key & 1) terrisctrl1_hdl4se_unit_PressKeyStart(pobj, TK_RIGHT); if (key & 2) terrisctrl1_hdl4se_unit_PressKeyStart(pobj, TK_LEFT); if (key & 4) terrisctrl1_hdl4se_unit_PressKeyStart(pobj, TK_DOWN); if (key & 8) terrisctrl1_hdl4se_unit_PressKeyStart(pobj, TK_TURNLEFT); } else { terrisctrl1_hdl4se_unit_Tick(pobj); } } else if (pobj->state == ST_CHECKBLOCKCANSETTO) { terrisctrl1_hdl4se_unit_BlockCanSetTo(pobj, ¤tblock, pobj->blockCanSetToContext.x, pobj->blockCanSetToContext.y); if (pobj->blockCanSetToContext.complete) { pobj->state = pobj->blockCanSetToContext.nextstate; pobj->blockCanSetToContext.BlockCanSetToPro(pobj); } } else if (pobj->state == ST_BLOCKWRITE) { terrisctrl1_hdl4se_unit_BlockWrite(pobj); if (pobj->genContext.complete) { pobj->state = ST_CHECKLINE; pobj->genContext.complete = 0; pobj->genContext.index = 0; pobj->genContext.count = 0; } } else if (pobj->state == ST_CHECKLINE) { terrisctrl1_hdl4se_unit_CheckLine(pobj); } else if (pobj->state == ST_COPYLINES) { terrisctrl1_hdl4se_unit_CopyLines(pobj); } else { pobj->state = ST_FLUSHTODISP; } return 0; } static int terrisctrl1_hdl4se_unit_Setup(HOBJECT object) { sTerrisCtrl1* pobj; pobj = (sTerrisCtrl1*)objectThis(object); pobj->laststate = pobj->state; pobj->write_reg = pobj->write; pobj->writeaddr_reg = pobj->writeaddr; pobj->writedata_reg = pobj->writedata; pobj->readaddr_reg = pobj->readaddr; return 0; }