diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-09-24 16:51:51 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-09-24 18:47:13 +0300 |
| commit | fecb86f6093c1e8aed6ab05c29c5af9d0cb93157 (patch) | |
| tree | 10171c839d77167fc98fbae0b315d2c87aa13fa5 /src/components/cpu/riscv/simple_riscv64.c | |
| parent | b1d67364b4b4832b8efed112f7b0ead1a0b3cd3b (diff) | |
| download | gran-fecb86f6093c1e8aed6ab05c29c5af9d0cb93157.tar.gz gran-fecb86f6093c1e8aed6ab05c29c5af9d0cb93157.zip | |
initial work towards message passing interface
+ As they are currently implemented, grid *may* get stuck if two nodes
try to send to eachother at the same time, I should probably add in
some kind of input buffer as well
Diffstat (limited to 'src/components/cpu/riscv/simple_riscv64.c')
| -rw-r--r-- | src/components/cpu/riscv/simple_riscv64.c | 207 |
1 files changed, 121 insertions, 86 deletions
diff --git a/src/components/cpu/riscv/simple_riscv64.c b/src/components/cpu/riscv/simple_riscv64.c index be96e60..987838e 100644 --- a/src/components/cpu/riscv/simple_riscv64.c +++ b/src/components/cpu/riscv/simple_riscv64.c @@ -9,8 +9,13 @@ #include <gran/cpu/riscv/simple_riscv64.h> -struct simple_rv64_ldst { - struct packet *pkt; +enum ldst_state { + LDST_IDLE, LDST_BLOCKED, LDST_SENT, LDST_DONE +}; + +struct ldst { + struct packet pkt; + enum ldst_state state; uint32_t reg; bool u; }; @@ -21,8 +26,10 @@ struct simple_riscv64 { struct component *imem; struct component *dmem; - struct simple_rv64_ldst dls; - struct simple_rv64_ldst ils; + struct ldst dls; + struct ldst ils; + + uint64_t rcv; /* have to be careful with x0 */ uint64_t regs[32]; @@ -396,25 +403,31 @@ static stat load(struct simple_riscv64 *cpu, union rv_insn insn) /* LH/LHU */ case 0b101: u = true; /* fallthrough */ case 0b001: size = 2; break; - /* LW */ + /* LW/LWU */ + case 0b110: u = true; /* fallthrough */ case 0b010: size = 4; break; + /* LD */ case 0b011: size = 8; break; default: error("unknown LOAD width %x", insn.btype.funct3); return ENOSUCH; } - struct packet *pkt = create_packet(PACKET_READ, addr, size); - if (!pkt) - return EMEM; + struct packet pkt = create_packet(cpu->rcv, + addr, + size, + NULL, + PACKET_READ); - cpu->dls = (struct simple_rv64_ldst){pkt, insn.itype.rd, u}; - stat ret = read(cpu->dmem, pkt); - if (ret) - return ret; + cpu->dls = (struct ldst){pkt, LDST_SENT, insn.itype.rd, u}; + stat ret = SEND(cpu, cpu->dmem, pkt); + if (ret == EBUSY) { + cpu->dls.state = LDST_BLOCKED; + ret = OK; + } cpu->pc += 4; - return OK; + return ret; } #define STYPE_IMM(insn) \ @@ -428,66 +441,58 @@ static stat store(struct simple_riscv64 *cpu, union rv_insn insn) int64_t addr = base + imm; uint64_t src = get_reg(cpu, insn.stype.rs2); + uint64_t size = 0; switch (insn.stype.funct3) { /* SB */ - case 0b000: { - cpu->dls.pkt = create_packet(PACKET_WRITE, addr, 1); - *(uint8_t *)packet_data(cpu->dls.pkt) = src; - break; - } + case 0b000: size = 1; break; /* SH */ - case 0b001: { - cpu->dls.pkt = create_packet(PACKET_WRITE, addr, 2); - *(uint16_t *)packet_data(cpu->dls.pkt) = src; - break; - } + case 0b001: size = 2; break; /* SW */ - case 0b010: { - cpu->dls.pkt = create_packet(PACKET_WRITE, addr, 4); - *(uint32_t *)packet_data(cpu->dls.pkt) = src; - break; - } + case 0b010: size = 4; break; /* SD */ - case 0b011: { - cpu->dls.pkt = create_packet(PACKET_WRITE, addr, 8); - *(uint64_t *)packet_data(cpu->dls.pkt) = src; - break; - } + case 0b011: size = 8; break; default: error("unknown width of STORE %x", insn.stype.funct3); return ENOSUCH; } + struct packet pkt = create_packet(cpu->rcv, addr, size, &src, PACKET_WRITE); + cpu->dls = (struct ldst){pkt, LDST_SENT, 0, false}; + stat ret = SEND(cpu, cpu->dmem, pkt); + if (ret == EBUSY) { + cpu->dls.state = LDST_BLOCKED; + ret = OK; + } + cpu->pc += 4; - return write(cpu->dmem, cpu->dls.pkt); + return ret; } static void finalize_ld(struct simple_riscv64 *cpu) { - struct simple_rv64_ldst ld = cpu->dls; + struct ldst ld = cpu->dls; uint64_t val = 0; - void *data = packet_data(ld.pkt); - switch (packet_size(ld.pkt)) { + switch (packet_convsize(&ld.pkt)) { case 1: - if (ld.u) val = *(uint8_t *)data; - else val = *(int8_t *)data; + if (ld.u) val = packet_convu8(&ld.pkt); + else val = packet_convi8(&ld.pkt); break; - case 2: if (ld.u) val = *(uint16_t *)data; - else val = *(int16_t *)data; + case 2: if (ld.u) val = packet_convu16(&ld.pkt); + else val = packet_convi16(&ld.pkt); break; - case 4: if (ld.u) val = *(uint32_t *)data; - else val = *(int32_t *)data; + case 4: if (ld.u) val = packet_convi32(&ld.pkt); + else val = packet_convu32(&ld.pkt); break; - case 8: val = *(uint64_t *)data; + case 8: val = packet_convu64(&ld.pkt); break; default: - error("unknown load size %zu", packet_size(ld.pkt)); + error("unknown load size %zu", packet_convsize(&ld.pkt)); } set_reg(cpu, ld.reg, val); @@ -501,58 +506,97 @@ static void finalize_st(struct simple_riscv64 *cpu) static void finalize_dls(struct simple_riscv64 *cpu) { - struct packet *pkt = cpu->dls.pkt; + cpu->dls.state = LDST_IDLE; + struct packet pkt = cpu->dls.pkt; - if (packet_type(pkt) == PACKET_READ) + if (is_set(&pkt, PACKET_READ)) finalize_ld(cpu); - else if (packet_type(pkt) == PACKET_WRITE) + else if (is_set(&pkt, PACKET_WRITE)) finalize_st(cpu); else error("unsupported packet type for simple_riscv64"); - - destroy_packet(pkt); - cpu->dls.pkt = NULL; } static uint32_t finalize_ils(struct simple_riscv64 *cpu) { - uint32_t insn = *(uint32_t *)packet_data(cpu->ils.pkt); - destroy_packet(cpu->ils.pkt); - cpu->ils.pkt = NULL; - return insn; + cpu->ils.state = LDST_IDLE; + return packet_convu32(&cpu->ils.pkt); +} + +static stat simple_riscv64_receive(struct simple_riscv64 *cpu, struct component *from, struct packet pkt) +{ + (void)from; + + if (pkt.to == cpu->rcv) { + cpu->dls.pkt = pkt; + cpu->dls.state = LDST_DONE; + return OK; + } + else if (pkt.to == cpu->rcv + 64) { + cpu->ils.pkt = pkt; + cpu->ils.state = LDST_DONE; + return OK; + } + else { + error("illegal receive on %s", cpu->component.name); + return EBUS; + } } static stat simple_riscv64_clock(struct simple_riscv64 *cpu) { /* there's an active data transfer we should handle */ - if (cpu->dls.pkt) { - assert(packet_state(cpu->dls.pkt) != PACKET_FAILED); + if (cpu->dls.state != LDST_IDLE) { + assert(!is_set(&cpu->dls.pkt, PACKET_ERROR)); + + if (cpu->dls.state == LDST_BLOCKED) { + stat r = SEND(cpu, cpu->dmem, cpu->dls.pkt); + if (r == EBUSY) + return OK; - if (packet_state(cpu->dls.pkt) == PACKET_DONE) + cpu->dls.state = LDST_SENT; + return OK; + } + + if (cpu->dls.state == LDST_SENT) + return OK; + + if (cpu->dls.state == LDST_DONE) { finalize_dls(cpu); - else /* wait for data */ + cpu->dls.state = LDST_IDLE; + } + else return OK; } - if (!cpu->ils.pkt) { - cpu->ils.pkt = - create_packet(PACKET_READ, cpu->pc, sizeof(uint32_t)); - if (!cpu->ils.pkt) - return EMEM; + if (cpu->ils.state == LDST_BLOCKED) { + stat ret = SEND(cpu, cpu->imem, cpu->ils.pkt); + if (ret == EBUSY) + return OK; - stat ret = read(cpu->imem, cpu->ils.pkt); - if (ret) - return ret; + return OK; } uint32_t insn = 0; - if (cpu->ils.pkt) { - assert(packet_state(cpu->ils.pkt) != PACKET_FAILED); + if (cpu->ils.state == LDST_DONE) { + assert(!is_set(&cpu->dls.pkt, PACKET_ERROR)); - if (packet_state(cpu->ils.pkt) == PACKET_DONE) - insn = finalize_ils(cpu); - else /* wait for instruction */ - return OK; + insn = finalize_ils(cpu); + cpu->ils.state = LDST_IDLE; + } + + if (cpu->ils.state == LDST_IDLE) { + cpu->ils.pkt = create_packet(cpu->rcv + 64, + cpu->pc, + sizeof(uint32_t), + NULL, + PACKET_READ); + cpu->ils.state = LDST_SENT; + stat ret = SEND(cpu, cpu->imem, cpu->ils.pkt); + if (ret == EBUSY) { + cpu->ils.state = LDST_BLOCKED; + return ret; + } } // for now assume little endian emulated and host cpu @@ -586,23 +630,12 @@ static stat simple_riscv64_clock(struct simple_riscv64 *cpu) static void simple_riscv64_destroy(struct simple_riscv64 *cpu) { - /* oh yeah, will have to think about the name stuff, - * i.e. how and where to free it, and where to assign it */ destroy(cpu->imem); - - if (cpu->imem != cpu->dmem) - destroy(cpu->dmem); - - if (cpu->ils.pkt) - destroy_packet(cpu->ils.pkt); - - if (cpu->dls.pkt) - destroy_packet(cpu->dls.pkt); - + destroy(cpu->dmem); free(cpu); } -struct component *create_simple_riscv64(uint32_t start_pc, +struct component *create_simple_riscv64(uint64_t rcv, uint32_t start_pc, struct component *imem, struct component *dmem) { @@ -610,10 +643,12 @@ struct component *create_simple_riscv64(uint32_t start_pc, if (!new) return NULL; + new->component.receive = (receive_callback)simple_riscv64_receive; new->component.clock = (clock_callback)simple_riscv64_clock; new->component.destroy = (destroy_callback)simple_riscv64_destroy; new->pc = start_pc; + new->rcv = rcv; new->imem = imem; new->dmem = dmem; return (struct component *)new; |
